package com.caijb.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 1、线程生命周期
 * 创建 -> 就绪 - -> 运行 - -> 阻塞（让出cpu） -> 死亡
 * 阻塞恢复后进入就绪状态 -> 等待cpu调度
 * 2、线程同步和互斥
 * 线程的同步是让线程按照一定的顺序执行，确保多个线程在访问共享资源时，不会产生数据不一致的问题。
 * 线程的互斥是保证多个线程不能同时访问共享资源，从而避免数据不一致的问题。
 * 3、在Java多线程编程中，notifyAll()和notify()都是用于唤醒等待在对象上的线程的方法，但它们之间有一些区别：
 * notify()方法：
 * notify()方法用于唤醒等待在对象上的单个线程，如果有多个线程在该对象上等待，则只会唤醒其中一个线程，但无法确定唤醒的是哪个线程。
 * 被唤醒的线程会从wait()方法返回，继续执行，直到抢占到对象的锁为止。
 * notifyAll()方法：
 * notifyAll()方法用于唤醒等待在对象上的所有线程，即唤醒所有等待该对象的线程。
 * 被唤醒的线程会竞争对象的锁，只有获得锁的线程才能继续执行，其他线程仍然会处于等待状态。
 * 总的来说，notify()方法唤醒一个等待线程，而notifyAll()方法会唤醒所有等待线程。
 * 通常情况下，推荐使用notifyAll()来唤醒等待线程，以确保所有线程有机会竞争锁并继续执行，避免出现死锁或饥饿现象。
 * 不过，在某些情况下，如果只需要唤醒一个线程，且能够确定被唤醒的线程，可以使用notify()方法。
 *
 * @author caijb
 * @version 1.0
 * @data 2025/10/25 12:00
 */
public class ThreadDemo {

    public static final Object LOCK = new Object();
    private static final Lock REENTRANT_LOCK = new ReentrantLock();
    private static final Condition CONDITION = REENTRANT_LOCK.newCondition();
    
    public static int count = 1;
    public static void main(String[] args) throws InterruptedException {
        // join方法演示
//        joinDemo();
        // sleep方法演示
//        sleepDemo();
        // 线程中断演示
//        interruptDemo();
        // 线程让步
//        yieldDemo();
        // 线程优先级
//        priorityDemo();
        // 守护线程
//        daemonThreadDemo();
        // 父子线程演示
//        inheritableThreadLocalDemo();
//        lifeDemo();
//        syncDemo();
//        syncConditionDemo();
//        parkDemo();
    }

    /**
     * 父子线程演示
     */
    private static void inheritableThreadLocalDemo() {
        UserThreadLocal.set("张三");
        UserThreadLocal.setInheritable("李四");
        Thread childThread = new Thread(() -> {
            System.out.println("子线程开始执行");
            System.out.println("子线程获取的父线程变量：" + UserThreadLocal.get());
            UserThreadLocal.setInheritable("王五");
            System.out.println("子线程改变变量：" + UserThreadLocal.getInheritable());
            System.out.println("子线程获取的子线程变量：" + UserThreadLocal.getInheritable());
        });
        childThread.start();
        try {
            childThread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("父线程开始执行");
        System.out.println("父线程获取的父线程变量：" + UserThreadLocal.get());
        System.out.println("父线程获取的子线程变量：" + UserThreadLocal.getInheritable());
    }

    /**
     * 1. 基本概念
     * 守护线程：是一种在后台运行的线程，当所有非守护线程结束时，JVM会自动退出，不会等待守护线程执行完毕
     * 用户线程：普通的应用线程，JVM会等待所有用户线程执行完毕才退出
     * 2. 主要特点
     * 守护线程具有"服务"性质，为主程序提供后台服务
     * 当JVM中只剩下守护线程时，虚拟机就会退出
     * 守护线程通常用于垃圾回收、内存管理等系统服务
     * 3. 相关方法
     * setDaemon(boolean on): 设置线程是否为守护线程
     * isDaemon(): 判断线程是否为守护线程
     */
    private static void daemonThreadDemo() {
        Thread daemonThread = new Thread(() -> {
            while (true) {
                System.out.println("守护线程正在运行...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                }
            }
        });

        // 设置为守护线程（必须在start之前设置）
        daemonThread.setDaemon(true);
        daemonThread.start();

        // 主线程执行一些任务
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("主线程执行完毕，JVM即将退出");
        // 当主线程结束时，由于守护线程还在运行，但JVM会直接退出
    }

    //线程优先级只是建议性的，不保证绝对的执行顺序
    //实际调度取决于操作系统和JVM实现
    //高优先级线程获得更多CPU时间片的概率更大
    //不应完全依赖优先级来控制线程执行顺序
    private static void priorityDemo() {
        // 创建高优先级线程
        Thread highPriorityThread = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("高优先级线程执行: " + i);
            }
        }, "HighPriorityThread");
        highPriorityThread.setPriority(Thread.MAX_PRIORITY);

        // 创建低优先级线程
        Thread lowPriorityThread = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("低优先级线程执行: " + i);
            }
        }, "LowPriorityThread");
        lowPriorityThread.setPriority(Thread.MIN_PRIORITY);

        // 创建默认优先级线程
        Thread normalPriorityThread = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("默认优先级线程执行: " + i);
            }
        }, "NormalPriorityThread");
        normalPriorityThread.setPriority(Thread.NORM_PRIORITY);

        // 启动所有线程
        highPriorityThread.start();
        lowPriorityThread.start();
        normalPriorityThread.start();
    }


    /**
     * 让出cpu执行权，进入就绪状态
     */
    private static void yieldDemo() {
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("线程" + Thread.currentThread().getName() + "执行中...");
                Thread.yield();
            }
        }).start();
    }

    /**
     * Thread.interrupt(): 设置目标线程的中断状态为true
     * Thread.isInterrupted(): 检查当前线程是否被中断
     * Thread.interrupted(): 检查当前线程是否被中断，并清除中断状态
     */
    private static void interruptDemo() {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                // 不是中断状态
                System.out.println("线程正常执行");
            }
            System.out.println(Thread.currentThread().isInterrupted());
            System.out.println(Thread.interrupted());
            System.out.println("线程被中断");
            System.out.println(Thread.currentThread().isInterrupted());
        });
        thread.start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        thread.interrupt();
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("主线程执行完毕");

    }

    private static void sleepDemo() {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("线程开始执行");
                Thread.sleep(5000);
                System.out.println("线程执行完毕");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        thread.start();
        System.out.println("主线程执行完毕");
    }

    /**
     * 阻塞当前线程，知道join线程执行完毕
     */
    private static void joinDemo() {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("线程执行完毕");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("线程2执行完毕");
        });
        thread2.start();
        thread.start();
        try {
            thread2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("主线程执行完毕");
    }

    /**
     * 线程阻塞demo
     */
    private static void parkDemo() throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("线程开始执行");
            LockSupport.park();
            boolean interrupted = Thread.interrupted();
            System.out.println("线程被中断：" + interrupted);
            boolean interrupted2 = Thread.interrupted();
            System.out.println("线程被中断：" + interrupted2);
        });
        thread.start();
        Thread.sleep(5000);
        thread.interrupt();
//        LockSupport.unpark(thread);
    }


    private static void syncConditionDemo() {
        Thread thread = new Thread(() -> {
            doSyncCondition(1);
        }, "线程1");
        Thread thread2 = new Thread(() -> {
            doSyncCondition(2);
        }, "线程2");
        Thread thread3 = new Thread(() -> {
            doSyncCondition(0);
        }, "线程3");
        thread.start();
        thread2.start();
        thread3.start();
    }

    private static void doSyncCondition(int i) {
        while (count <= 100) {
            REENTRANT_LOCK.lock();
            try {
                if (count % 3 == i) {
                    System.out.println(Thread.currentThread().getName() + ": " + count);
                    count++;
                }
                CONDITION.signalAll();
                CONDITION.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                REENTRANT_LOCK.unlock();
            }
        }
    }

    /**
     * 线程生命周期
     */
    private static void lifeDemo() {
        Runnable runnable = () -> {
            System.out.println("进入线程执行状态");
            System.out.println("线程进入阻塞状态");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("线程被中断");
            }
            System.out.println("线程阻塞五秒后 恢复就绪状态");
            System.out.println("线程执行完毕，当前线程死亡");
        };
        // 创建线程
        Thread thread = new Thread(runnable);
        System.out.println("线程创建完毕");
        // 进入就绪状态
        thread.start();
        System.out.println("线程进入就绪状态");
    }

    /**
     * 线程同步
     */
    private static void syncDemo() { 
        Thread thread = new Thread(() -> {
            sync(1);
        }, "线程1");
        Thread thread2 = new Thread(() -> {
            sync(2);
        }, "线程2");
        Thread thread3 = new Thread(() -> {
            sync(0);
        }, "线程3");
        thread.start();
        thread2.start();
        thread3.start();
    }

    private static void sync(int i) {
        while (count <= 100) {
            synchronized (ThreadDemo.LOCK) {
                if (count % 3 == i) {
                    System.out.println(Thread.currentThread().getName() + ": " + count);
                    count++;
                    LOCK.notifyAll();
                } else {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
